package com.tencent.wxcloudrun.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.eventbus.EventBus;
import com.tencent.wxcloudrun.constant.RedisKeyConstant;
import com.tencent.wxcloudrun.domain.TActiJoin;
import com.tencent.wxcloudrun.dto.ActiJoinProdAttrReqDTO;
import com.tencent.wxcloudrun.dto.ActiJoinProdAttrResDTO;
import com.tencent.wxcloudrun.dto.ActiJoinProdReqDTO;
import com.tencent.wxcloudrun.dto.ActiJoinProdResDTO;
import com.tencent.wxcloudrun.enums.ActiJoinKindEnum;
import com.tencent.wxcloudrun.enums.ActiJoinStatEnum;
import com.tencent.wxcloudrun.enums.ActiJoinTypeEnum;
import com.tencent.wxcloudrun.exception.BusinessException;
import com.tencent.wxcloudrun.mapper.TActiJoinMapper;
import com.tencent.wxcloudrun.service.TActiJoinService;
import com.tencent.wxcloudrun.util.RedisUtil;
import com.tencent.wxcloudrun.util.RedissonUtil;
import com.tencent.wxcloudrun.vo.request.acti.ActiJoinBlackReqVo;
import com.tencent.wxcloudrun.vo.request.acti.ActiJoinReqVo;
import com.tencent.wxcloudrun.vo.request.acti.ActiJoinSelectedReqVo;
import com.tencent.wxcloudrun.vo.response.acti.ActiJoinBlackResVo;
import com.tencent.wxcloudrun.vo.response.acti.ActiJoinResVo;
import com.tencent.wxcloudrun.vo.response.acti.ActiJoinSelectedResVo;

import lombok.extern.slf4j.Slf4j;

/**
 * @author ziyin.zhao
 * @description 针对表【t_acti_join(活动参选表)】的数据库操作Service实现
 * @createDate 2025-04-22 17:11:16
 */
@Slf4j
@Service
public class TActiJoinServiceImpl extends ServiceImpl<TActiJoinMapper, TActiJoin> implements TActiJoinService {

    @Resource
    private EventBus eventBus;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private RedissonUtil redissonUtil;

    @Override
    public void joinCheck(Long userId, Long actiId, Integer actiJoinType, Integer selectedFlag) {
        String actiJoinStatusStr = redisUtil.get(RedisKeyConstant.getActiJoinStatusRedisKey(actiId, userId));
        // 如果活动需入围 则校验用户状态是否为已入围
        if (selectedFlag == 1 && (!StringUtils.hasLength(actiJoinStatusStr)
            || actiJoinStatusStr.equals(String.valueOf(ActiJoinStatEnum.ALREADY_SELECTED_JOIN.getValue())))) {
            log.error("活动参选-未入围-用户ID={} 活动ID={}", userId, actiId);
            throw new BusinessException("您未入围，请勿参与活动");
        }

        if (StringUtils.hasLength(actiJoinStatusStr)) {
            if (actiJoinStatusStr.equals(String.valueOf(ActiJoinStatEnum.ALREADY_CHOOSE.getValue()))) {
                log.error("活动参选-重复参选-用户ID={} 活动ID={}", userId, actiId);
                throw new BusinessException("您已中选，请勿重复参选");
            }

            // 不为拼手速，均不允许重复参选
            if (ActiJoinTypeEnum.QUICK.getValue() != actiJoinType) {
                if (actiJoinStatusStr.equals(String.valueOf(ActiJoinStatEnum.ALREADY_JOIN.getValue()))) {
                    log.error("活动参选-重复参选-用户ID={} 活动ID={}", userId, actiId);
                    throw new BusinessException("您已参选，请勿重复参选");
                }
                if (actiJoinStatusStr.equals(String.valueOf(ActiJoinStatEnum.ALREADY_SELECTED_JOIN.getValue()))) {
                    log.error("活动参选-重复参选-用户ID={} 活动ID={}", userId, actiId);
                    throw new BusinessException("您已参选，请勿重复参选");
                }
            }
        }
    }

    @Override
    public void joinProdCheck(Long actiId, List<ActiJoinProdReqDTO> prodDTOList) {
        boolean hasSuccessFlag = false;
        for (ActiJoinProdReqDTO actiJoinProdReqDTO : prodDTOList) {
            // 如果商品属性为空则下一条
            if (CollectionUtils.isEmpty(actiJoinProdReqDTO.getProdAttrList())) {
                continue;
            }
            // 遍历商品属性，更新库存
            for (ActiJoinProdAttrReqDTO actiJoinProdAttrReqDTO : actiJoinProdReqDTO.getProdAttrList()) {
                String key = RedisKeyConstant.getActiJoinStockRedisKey(actiId, actiJoinProdReqDTO.getProdId(),
                    actiJoinProdAttrReqDTO.getProdAttrId());
                String stockStr = redisUtil.get(key);
                if (StringUtils.hasLength(stockStr)) {
                    int stock = Integer.parseInt(stockStr);
                    if (stock > 0) {
                        hasSuccessFlag = true;
                    }
                }
            }
        }
        if (!hasSuccessFlag) {
            throw new BusinessException("库存不足");
        }
    }

    @Override
    public void joinSelectedCheck(Long userId, Long actiId, Integer actiJoinType) {
        String actiJoinStatusStr = redisUtil.get(RedisKeyConstant.getActiJoinStatusRedisKey(actiId, userId));
        if (StringUtils.hasLength(actiJoinStatusStr)) {
            if (actiJoinStatusStr.equals(String.valueOf(ActiJoinStatEnum.ALREADY_CHOOSE.getValue()))) {
                log.error("活动参选-重复参选-用户ID={} 活动ID={}", userId, actiId);
                throw new BusinessException("您已中选，请勿重复参选");
            }

            if (actiJoinStatusStr.equals(String.valueOf(ActiJoinStatEnum.ALREADY_SELECTED.getValue()))) {
                log.error("活动参选-重复参选-用户ID={} 活动ID={}", userId, actiId);
                throw new BusinessException("您已入围，请勿重复参选");
            }

            // 不为拼手速，均不允许重复参选
            if (ActiJoinTypeEnum.QUICK.getValue() != actiJoinType) {
                if (actiJoinStatusStr.equals(String.valueOf(ActiJoinStatEnum.ALREADY_JOIN.getValue()))) {
                    log.error("活动参选-重复参选-用户ID={} 活动ID={}", userId, actiId);
                    throw new BusinessException("您已参选，请勿重复参选");
                }
                if (actiJoinStatusStr.equals(String.valueOf(ActiJoinStatEnum.ALREADY_SELECTED_JOIN.getValue()))) {
                    log.error("活动参选-重复参选-用户ID={} 活动ID={}", userId, actiId);
                    throw new BusinessException("您已参选，请勿重复参选");
                }
            }
        }
    }

    @Override
    public ActiJoinSelectedResVo joinSelectedToRedis(ActiJoinSelectedReqVo reqVo) {
        String lockKey = RedisKeyConstant.getActiJoinLockRedisKey(reqVo.getActiId());
        RLock lock = redissonUtil.getClint(lockKey);
        try {
            log.info("活动入围-分布式锁-开始上锁-用户ID={}", reqVo.getUserId());
            // 尝试获取锁，等待时间为 0 秒，锁超时为 5 秒
            if (lock.tryLock(0, 5, TimeUnit.SECONDS)) {
                log.info("活动入围-分布式锁-上锁成功-用户ID={}", reqVo.getUserId());
                try {
                    return joinSelectedToRedisDeal(reqVo);
                } finally {
                    lock.unlock();
                    log.info("活动入围-分布式锁-释放成功-用户ID={}", reqVo.getUserId());
                }
            } else {
                log.error("活动入围-分布式锁-获取失败-用户ID={}", reqVo.getUserId());
                throw new RuntimeException("获取分布式锁失败");
            }
        } catch (InterruptedException e) {
            log.error("活动入围-分布式锁-获取时被中断-用户ID={}", reqVo.getUserId());
            Thread.currentThread().interrupt();
            throw new RuntimeException("获取分布式锁时被中断", e);
        }
    }

    /**
     * @Author: ZhaoZiYin
     * @Date: 2025/4/30
     * @Params: [reqVo]
     * @Return: void
     * @Description: 入围活动参选处理
     */
    public ActiJoinSelectedResVo joinSelectedToRedisDeal(ActiJoinSelectedReqVo reqVo) {
        ActiJoinSelectedResVo resVo = new ActiJoinSelectedResVo();
        log.info("活动入围-开始处理-用户ID={}", reqVo.getUserId());

        redisUtil.set(RedisKeyConstant.getActiJoinStatusRedisKey(reqVo.getActiId(), reqVo.getUserId()),
            String.valueOf(ActiJoinStatEnum.ALREADY_SELECTED_JOIN.getValue()));

        if (reqVo.getSelectedJoinType() == ActiJoinTypeEnum.QUICK.getValue()) {
            // 手速：判断入围库存数量是否充足，实时生成入围名单
            String key = RedisKeyConstant.getActiSelectedStockRedisKey(reqVo.getActiId());
            int successFlag = this.updateRedis4ActiStock(key);
            if (successFlag == 1) {
                resVo.setSuccessFlag(successFlag);
                reqVo.setSuccessFlag(successFlag);
                redisUtil.set(RedisKeyConstant.getActiJoinStatusRedisKey(reqVo.getActiId(), reqVo.getUserId()),
                    String.valueOf(ActiJoinStatEnum.ALREADY_SELECTED.getValue()));
            }
        } else if (reqVo.getSelectedJoinType() == ActiJoinTypeEnum.SHAKE.getValue()) {
            // 摇号：获取当前号码
            Integer number = getActiJoinNumber(RedisKeyConstant.getActiSelectedNumberRedisKey(reqVo.getActiId()));
            reqVo.setNumber(number);
        }

        // 推送异步事件落库
        eventBus.post(reqVo);

        log.info("活动入围-处理结束-用户ID={}-是否中选={}", reqVo.getUserId(), resVo.getSuccessFlag());
        return resVo;
    }

    @Override
    public void joinSelected(ActiJoinSelectedReqVo reqVo) {
        TActiJoin actiJoin = new TActiJoin();
        actiJoin.setActiId(reqVo.getActiId());
        actiJoin.setUserId(reqVo.getUserId());
        actiJoin.setKind(ActiJoinKindEnum.SELECTED.getValue());
        actiJoin.setStatus(reqVo.getSuccessFlag() == 1 ? ActiJoinStatEnum.ALREADY_SELECTED.getValue()
            : ActiJoinStatEnum.ALREADY_SELECTED_JOIN.getValue());
        actiJoin.setNumber(reqVo.getNumber());
        actiJoin.setFileIdList(reqVo.getFileIdList());
        actiJoin.setTitle(reqVo.getTitle());
        actiJoin.setContent(reqVo.getContent());
        actiJoin.setCreatedBy(String.valueOf(reqVo.getUserId()));
        actiJoin.setCreatedTime(LocalDateTime.now());
        actiJoin.setUpdatedBy(String.valueOf(reqVo.getUserId()));
        actiJoin.setUpdatedTime(LocalDateTime.now());
        this.save(actiJoin);
    }

    @Override
    public ActiJoinResVo joinToRedis(ActiJoinReqVo reqVo) {
        ActiJoinResVo resVo = new ActiJoinResVo();
        log.info("活动参选-开始处理-用户ID={}", reqVo.getUserId());

        // 判断活动类型处理业务逻辑
        if (reqVo.getActiJoinType() == ActiJoinTypeEnum.QUICK.getValue()) {
            resVo = joinToRedisBathDeal4Quick(reqVo);
        } else if (reqVo.getActiJoinType() == ActiJoinTypeEnum.SHAKE.getValue()) {
            joinToRedisBathDeal4Shake(reqVo);
        }

        // 推送异步参选事件
        eventBus.post(reqVo);

        log.info("活动参选-处理结束-用户ID={}-出参={}", reqVo.getUserId(), JSONObject.toJSONString(resVo));
        return resVo;
    }

    /**
     * @Author: ZhaoZiYin
     * @Date: 2025/5/30
     * @Params: [reqVo]
     * @Return: ActiJoinResVo successFlag: 0-全部失败 1-全部成功 2-部分成功
     * @Description: 手速商品库存批量操作
     */
    public ActiJoinResVo joinToRedisBathDeal4Quick(ActiJoinReqVo reqVo) {
        ActiJoinResVo resVo = new ActiJoinResVo();
        resVo.setSuccessFlag(0);

        // 如果商品列表为空，直接返回
        if (CollectionUtils.isEmpty(reqVo.getProdList())) {
            return resVo;
        }

        // 至少一个成功
        boolean hasSuccessFlag = false;
        // 全部成功
        boolean allSuccessFlag = true;

        // 初始化返回的商品列表
        List<ActiJoinProdResDTO> prodList = new ArrayList<>(reqVo.getProdList().size());

        // 遍历请求中的商品列表
        for (ActiJoinProdReqDTO actiJoinProdReqDTO : reqVo.getProdList()) {
            ActiJoinProdResDTO resDTO = new ActiJoinProdResDTO();
            resDTO.setProdId(actiJoinProdReqDTO.getProdId());
            // 如果商品属性为空则下一条
            if (CollectionUtils.isEmpty(actiJoinProdReqDTO.getProdAttrList())) {
                prodList.add(resDTO);
                continue;
            }
            // 遍历商品属性，更新库存
            List<ActiJoinProdAttrResDTO> prodAttrList = new ArrayList<>(actiJoinProdReqDTO.getProdAttrList().size());
            for (ActiJoinProdAttrReqDTO actiJoinProdAttrReqDTO : actiJoinProdReqDTO.getProdAttrList()) {
                // 单笔操作
                int successFlag = joinToRedisDeal4Quick(reqVo.getUserId(), reqVo.getActiId(),
                    actiJoinProdReqDTO.getProdId(), actiJoinProdAttrReqDTO);
                ActiJoinProdAttrResDTO attrResDTO = new ActiJoinProdAttrResDTO();
                attrResDTO.setProdAttrId(actiJoinProdAttrReqDTO.getProdAttrId());
                attrResDTO.setName(actiJoinProdAttrReqDTO.getName());
                attrResDTO.setValue(actiJoinProdAttrReqDTO.getValue());
                attrResDTO.setSuccessFlag(successFlag);
                prodAttrList.add(attrResDTO);
                if (successFlag == 1) {
                    hasSuccessFlag = true;
                } else {
                    allSuccessFlag = false;
                }
            }
            resDTO.setProdAttrList(prodAttrList);
            prodList.add(resDTO);
        }
        resVo.setProdList(prodList);

        // 判断处理结果更新缓存状态
        if (!hasSuccessFlag) {
            resVo.setSuccessFlag(0);
        } else if (!allSuccessFlag) {
            resVo.setSuccessFlag(2);
            redisUtil.set(RedisKeyConstant.getActiJoinStatusRedisKey(reqVo.getActiId(), reqVo.getUserId()),
                String.valueOf(ActiJoinStatEnum.ALREADY_JOIN.getValue()));
        } else {
            resVo.setSuccessFlag(1);
            reqVo.setSuccessFlag(1);
            redisUtil.set(RedisKeyConstant.getActiJoinStatusRedisKey(reqVo.getActiId(), reqVo.getUserId()),
                String.valueOf(ActiJoinStatEnum.ALREADY_CHOOSE.getValue()));
        }
        return resVo;
    }

    /**
     * @Author: ZhaoZiYin
     * @Date: 2025/5/30
     * @Params: [userId, actiId, prodId, actiJoinProdAttrReqDTO]
     * @Return: boolean
     * @Description: 手速商品库存单笔操作
     */
    private int joinToRedisDeal4Quick(Long userId, Long actiId, Long prodId,
        ActiJoinProdAttrReqDTO actiJoinProdAttrReqDTO) {
        // 获取锁
        String lockKey =
            RedisKeyConstant.getActiJoinProdLockRedisKey(actiId, prodId, actiJoinProdAttrReqDTO.getProdAttrId());
        RLock lock = redissonUtil.getClint(lockKey);
        try {
            log.info("活动手速参选-分布式锁-开始上锁-用户ID={}-商品属性ID={}", userId, actiJoinProdAttrReqDTO.getProdAttrId());
            // 尝试获取锁，等待时间为 0 秒，锁超时为 5 秒
            if (lock.tryLock(0, 5, TimeUnit.SECONDS)) {
                log.info("活动手速参选-分布式锁-上锁成功-用户ID={}-商品属性ID={}", userId, actiJoinProdAttrReqDTO.getProdAttrId());
                try {
                    String stockKey = RedisKeyConstant.getActiJoinStockRedisKey(actiId, prodId,
                        actiJoinProdAttrReqDTO.getProdAttrId());
                    return updateRedis4ActiStock(stockKey);
                } finally {
                    lock.unlock();
                    log.info("活动手速参选-分布式锁-释放成功-用户ID={}-商品属性ID={}", userId, actiJoinProdAttrReqDTO.getProdAttrId());
                }
            } else {
                log.error("活动手速参选-分布式锁-获取失败-用户ID={}-商品属性ID={}", userId, actiJoinProdAttrReqDTO.getProdAttrId());
                return 0;
            }
        } catch (InterruptedException e) {
            log.error("活动手速参选-分布式锁-获取时被中断-用户ID={}-商品属性ID={}", userId, actiJoinProdAttrReqDTO.getProdAttrId());
            Thread.currentThread().interrupt();
            return 0;
        }
    }

    /**
     * @Author: ZhaoZiYin
     * @Date: 2025/5/30
     * @Params: [reqVo]
     * @Return: void
     * @Description: 摇号商品库存批量操作
     */
    public void joinToRedisBathDeal4Shake(ActiJoinReqVo reqVo) {
        for (ActiJoinProdReqDTO actiJoinProdReqDTO : reqVo.getProdList()) {
            for (ActiJoinProdAttrReqDTO actiJoinProdAttrReqDTO : actiJoinProdReqDTO.getProdAttrList()) {
                int number = joinToRedisDeal4Shake(reqVo.getUserId(), reqVo.getActiId(), actiJoinProdReqDTO.getProdId(),
                    actiJoinProdAttrReqDTO);
                actiJoinProdAttrReqDTO.setNumber(number);
            }
        }
        redisUtil.set(RedisKeyConstant.getActiJoinStatusRedisKey(reqVo.getActiId(), reqVo.getUserId()),
            String.valueOf(ActiJoinStatEnum.ALREADY_JOIN.getValue()));
    }

    /**
     * @Author: ZhaoZiYin
     * @Date: 2025/5/30
     * @Params: [userId, actiId, prodId, actiJoinProdAttrReqDTO]
     * @Return: int
     * @Description: 摇号商品库存单笔操作
     */
    private int joinToRedisDeal4Shake(Long userId, Long actiId, Long prodId,
        ActiJoinProdAttrReqDTO actiJoinProdAttrReqDTO) {
        // 获取锁
        String lockKey =
            RedisKeyConstant.getActiJoinProdLockRedisKey(actiId, prodId, actiJoinProdAttrReqDTO.getProdAttrId());
        RLock lock = redissonUtil.getClint(lockKey);
        try {
            log.info("活动摇号参选-分布式锁-开始上锁-用户ID={}-商品属性ID={}", userId, actiJoinProdAttrReqDTO.getProdAttrId());
            // 尝试获取锁，等待时间为 0 秒，锁超时为 5 秒
            if (lock.tryLock(0, 5, TimeUnit.SECONDS)) {
                log.info("活动摇号参选-分布式锁-上锁成功-用户ID={}", userId);
                try {
                    String key = RedisKeyConstant.getActiJoinNumberRedisKey(actiId, prodId,
                        actiJoinProdAttrReqDTO.getProdAttrId());
                    return getActiJoinNumber(key);
                } finally {
                    lock.unlock();
                    log.info("活动摇号参选-分布式锁-释放成功-用户ID={}-商品属性ID={}", userId, actiJoinProdAttrReqDTO.getProdAttrId());
                }
            } else {
                log.error("活动摇号参选-分布式锁-获取失败-用户ID={}-商品属性ID={}", userId, actiJoinProdAttrReqDTO.getProdAttrId());
                throw new RuntimeException("获取分布式锁失败");
            }
        } catch (InterruptedException e) {
            log.error("活动摇号参选-分布式锁-获取时被中断-用户ID={}-商品属性ID={}", userId, actiJoinProdAttrReqDTO.getProdAttrId());
            Thread.currentThread().interrupt();
            throw new RuntimeException("获取分布式锁时被中断", e);
        }
    }

    /**
     * @Author: ZhaoZiYin
     * @Date: 2025/4/30
     * @Params: [actiId, prodId, prodAttrId]
     * @Return: int
     * @Description: 单笔更新商品库存
     */
    private int updateRedis4ActiStock(String key) {
        String stockStr = redisUtil.get(key);
        if (StringUtils.hasLength(stockStr)) {
            int stock = Integer.parseInt(stockStr);
            if (stock > 0) {
                redisUtil.set(key, String.valueOf(stock - 1));
                return 1;
            }
        }
        return 0;
    }

    /**
     * @Author: ZhaoZiYin
     * @Date: 2025/4/27
     * @Params: [actiId]
     * @Return: String
     * @Description: 单笔更新商品号码
     */
    private Integer getActiJoinNumber(String key) {
        String number = redisUtil.get(key);
        if (StringUtils.hasLength(number)) {
            number = String.valueOf(Integer.parseInt(number) + 1);
        } else {
            number = "1";
        }
        redisUtil.set(key, number);
        return Integer.parseInt(number);
    }

    @Override
    public void joinToDb(ActiJoinReqVo reqVo) {
        TActiJoin actiJoin = new TActiJoin();
        actiJoin.setActiId(reqVo.getActiId());
        actiJoin.setUserId(reqVo.getUserId());
        actiJoin.setKind(ActiJoinKindEnum.JOIN.getValue());
        actiJoin.setStatus(reqVo.getSuccessFlag() == 1 ? ActiJoinStatEnum.ALREADY_CHOOSE.getValue()
            : ActiJoinStatEnum.ALREADY_JOIN.getValue());
        actiJoin.setNumber(reqVo.getNumber());
        actiJoin.setFileIdList(reqVo.getFileIdList());
        actiJoin.setTitle(reqVo.getTitle());
        actiJoin.setContent(reqVo.getContent());
        actiJoin.setCreatedBy(String.valueOf(reqVo.getUserId()));
        actiJoin.setCreatedTime(LocalDateTime.now());
        actiJoin.setUpdatedBy(String.valueOf(reqVo.getUserId()));
        actiJoin.setUpdatedTime(LocalDateTime.now());
        this.save(actiJoin);
    }

    @Override
    public ActiJoinBlackResVo joinBlackToRedis(ActiJoinBlackReqVo reqVo) {
        String lockKey = RedisKeyConstant.getActiJoinLockRedisKey(reqVo.getActiId());
        RLock lock = redissonUtil.getClint(lockKey);
        try {
            log.info("活动黑箱-分布式锁-开始上锁-用户ID={}", reqVo.getUserId());
            // 尝试获取锁，等待时间为 0 秒，锁超时为 5 秒
            if (lock.tryLock(0, 5, TimeUnit.SECONDS)) {
                log.info("活动黑箱-分布式锁-上锁成功-用户ID={}", reqVo.getUserId());
                try {
                    return joinBlackToRedisDeal(reqVo);
                } finally {
                    lock.unlock();
                    log.info("活动黑箱-分布式锁-释放成功-用户ID={}", reqVo.getUserId());
                }
            } else {
                log.error("活动黑箱-分布式锁-获取失败-用户ID={}", reqVo.getUserId());
                throw new RuntimeException("获取分布式锁失败");
            }
        } catch (InterruptedException e) {
            log.error("活动黑箱-分布式锁-获取时被中断-用户ID={}", reqVo.getUserId());
            Thread.currentThread().interrupt();
            throw new RuntimeException("获取分布式锁时被中断", e);
        }
    }

    /**
     * @Author: ZhaoZiYin
     * @Date: 2025/4/30
     * @Params: [reqVo]
     * @Return: boolean
     * @Description: 活动黑箱参选处理
     */
    public ActiJoinBlackResVo joinBlackToRedisDeal(ActiJoinBlackReqVo reqVo) {
        ActiJoinBlackResVo resVo = new ActiJoinBlackResVo();
        log.info("活动黑箱-开始处理-用户ID={}", reqVo.getUserId());

        // 判断是否中选，如果中选，则生成中选名单
        String key = RedisKeyConstant.getActiBlackStockRedisKey(reqVo.getActiId());
        int successFlag = this.updateRedis4ActiStock(key);
        if (successFlag == 1) {
            resVo.setSuccessFlag(successFlag);
            reqVo.setSuccessFlag(successFlag);
            redisUtil.set(RedisKeyConstant.getActiJoinStatusRedisKey(reqVo.getActiId(), reqVo.getUserId()),
                String.valueOf(ActiJoinStatEnum.ALREADY_CHOOSE.getValue()));
        }

        // 推送异步事件落库
        eventBus.post(reqVo);

        log.info("活动黑箱-处理结束-用户ID={}-是否中选={}", reqVo.getUserId(), successFlag);
        return resVo;
    }

    @Override
    public void joinBlack(ActiJoinBlackReqVo reqVo) {
        TActiJoin actiJoin = new TActiJoin();
        actiJoin.setActiId(reqVo.getActiId());
        actiJoin.setUserId(reqVo.getUserId());
        actiJoin.setKind(ActiJoinKindEnum.BLACK.getValue());
        actiJoin.setStatus(reqVo.getSuccessFlag() == 1 ? ActiJoinStatEnum.ALREADY_CHOOSE.getValue()
            : ActiJoinStatEnum.ALREADY_BLACK_JOIN.getValue());
        actiJoin.setCreatedBy(String.valueOf(reqVo.getUserId()));
        actiJoin.setCreatedTime(LocalDateTime.now());
        actiJoin.setUpdatedBy(String.valueOf(reqVo.getUserId()));
        actiJoin.setUpdatedTime(LocalDateTime.now());
        this.save(actiJoin);
    }

    @Override
    public void deleteJoin(Long actiId, Long userId, Integer kind) {
        LambdaQueryWrapper<TActiJoin> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TActiJoin::getActiId, actiId);
        queryWrapper.eq(TActiJoin::getUserId, userId);
        queryWrapper.eq(TActiJoin::getKind, kind);
        queryWrapper.eq(TActiJoin::getEnableFlag, 1);
        this.remove(queryWrapper);
    }

    @Override
    public List<TActiJoin> actiSelectedEnd(Long actiId, List<Integer> numberList) {
        LambdaQueryWrapper<TActiJoin> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TActiJoin::getActiId, actiId);
        queryWrapper.eq(TActiJoin::getKind, ActiJoinKindEnum.SELECTED.getValue());
        queryWrapper.in(TActiJoin::getNumber, numberList);
        queryWrapper.eq(TActiJoin::getEnableFlag, 1);
        List<TActiJoin> actiJoinList = this.list(queryWrapper);
        if (!CollectionUtils.isEmpty(actiJoinList)) {
            for (TActiJoin actiJoin : actiJoinList) {
                actiJoin.setStatus(ActiJoinStatEnum.ALREADY_SELECTED.getValue());
                actiJoin.setUpdatedTime(LocalDateTime.now());
            }
            this.updateBatchById(actiJoinList);
        }
        return actiJoinList;
    }

    @Override
    public void actiEnd(Long actiId, List<Long> userIdList) {
        LambdaQueryWrapper<TActiJoin> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TActiJoin::getActiId, actiId);
        queryWrapper.eq(TActiJoin::getKind, ActiJoinKindEnum.JOIN.getValue());
        queryWrapper.in(TActiJoin::getUserId, userIdList);
        queryWrapper.eq(TActiJoin::getEnableFlag, 1);
        List<TActiJoin> actiJoinList = this.list(queryWrapper);
        if (!CollectionUtils.isEmpty(actiJoinList)) {
            for (TActiJoin actiJoin : actiJoinList) {
                actiJoin.setStatus(ActiJoinStatEnum.ALREADY_CHOOSE.getValue());
                actiJoin.setUpdatedTime(LocalDateTime.now());
            }
            this.updateBatchById(actiJoinList);
        }
    }

}
